#ifndef __EXECUTABLE__
#define __EXECUTABLE__

#include "../lib/define.h"

#define IMAGE_DOS_SIGNATURE 0x4D5A    // MZ
#define IMAGE_OS2_SIGNATURE 0x4E45    // NE
#define IMAGE_OS2_SIGNATURE_LE 0x4C45 // LE
#define IMAGE_NT_SIGNATURE 0x50450000 // PE00

typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
  WORD e_magic;                    // Magic number
  WORD e_cblp;                     // Bytes on last page of file
  WORD e_cp;                       // Pages in file
  WORD e_crlc;                     // Relocations
  WORD e_cparhdr;                  // Size of header in paragraphs
  WORD e_minalloc;                 // Minimum extra paragraphs needed
  WORD e_maxalloc;                 // Maximum extra paragraphs needed
  WORD e_ss;                       // Initial (relative) SS value
  WORD e_sp;                       // Initial SP value
  WORD e_csum;                     // Checksum
  WORD e_ip;                       // Initial IP value
  WORD e_cs;                       // Initial (relative) CS value
  WORD e_lfarlc;                   // File address of relocation table
  WORD e_ovno;                     // Overlay number
  WORD e_res[4];                   // Reserved words
  WORD e_oemid;                    // OEM identifier (for e_oeminfo)
  WORD e_oeminfo;                  // OEM information; e_oemid specific
  WORD e_res2[10];                 // Reserved words
  LONG e_lfanew;                   // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

typedef struct _IMAGE_OS2_HEADER { // OS/2 .EXE header
  WORD ne_magic;                   // Magic number
  CHAR ne_ver;                     // Version number
  CHAR ne_rev;                     // Revision number
  WORD ne_enttab;                  // Offset of Entry Table
  WORD ne_cbenttab;                // Number of bytes in Entry Table
  LONG ne_crc;                     // Checksum of whole file
  WORD ne_flags;                   // Flag word
  WORD ne_autodata;                // Automatic data segment number
  WORD ne_heap;                    // Initial heap allocation
  WORD ne_stack;                   // Initial stack allocation
  LONG ne_csip;                    // Initial CS:IP setting
  LONG ne_sssp;                    // Initial SS:SP setting
  WORD ne_cseg;                    // Count of file segments
  WORD ne_cmod;                    // Entries in Module Reference Table
  WORD ne_cbnrestab;               // Size of non-resident name table
  WORD ne_segtab;                  // Offset of Segment Table
  WORD ne_rsrctab;                 // Offset of Resource Table
  WORD ne_restab;                  // Offset of resident name table
  WORD ne_modtab;                  // Offset of Module Reference Table
  WORD ne_imptab;                  // Offset of Imported Names Table
  LONG ne_nrestab;                 // Offset of Non-resident Names Table
  WORD ne_cmovent;                 // Count of movable entries
  WORD ne_align;                   // Segment alignment shift count
  WORD ne_cres;                    // Count of resource segments
  BYTE ne_exetyp;                  // Target Operating system
  BYTE ne_flagsothers;             // Other .EXE flags
  WORD ne_pretthunks;              // offset to return thunks
  WORD ne_psegrefbytes;            // offset to segment ref. bytes
  WORD ne_swaparea;                // Minimum code swap area size
  WORD ne_expver;                  // Expected Windows version number
} IMAGE_OS2_HEADER, *PIMAGE_OS2_HEADER;

typedef struct _IMAGE_VXD_HEADER { // Windows VXD header
  WORD e32_magic;                  // Magic number
  BYTE e32_border;                 // The byte ordering for the VXD
  BYTE e32_worder;                 // The word ordering for the VXD
  DWORD e32_level;                 // The EXE format level for now = 0
  WORD e32_cpu;                    // The CPU type
  WORD e32_os;                     // The OS type
  DWORD e32_ver;                   // Module version
  DWORD e32_mflags;                // Module flags
  DWORD e32_mpages;                // Module # pages
  DWORD e32_startobj;              // Object # for instruction pointer
  DWORD e32_eip;                   // Extended instruction pointer
  DWORD e32_stackobj;              // Object # for stack pointer
  DWORD e32_esp;                   // Extended stack pointer
  DWORD e32_pagesize;              // VXD page size
  DWORD e32_lastpagesize;          // Last page size in VXD
  DWORD e32_fixupsize;             // Fixup section size
  DWORD e32_fixupsum;              // Fixup section checksum
  DWORD e32_ldrsize;               // Loader section size
  DWORD e32_ldrsum;                // Loader section checksum
  DWORD e32_objtab;                // Object table offset
  DWORD e32_objcnt;                // Number of objects in module
  DWORD e32_objmap;                // Object page map offset
  DWORD e32_itermap;               // Object iterated data map offset
  DWORD e32_rsrctab;               // Offset of Resource Table
  DWORD e32_rsrccnt;               // Number of resource entries
  DWORD e32_restab;                // Offset of resident name table
  DWORD e32_enttab;                // Offset of Entry Table
  DWORD e32_dirtab;                // Offset of Module Directive Table
  DWORD e32_dircnt;                // Number of module directives
  DWORD e32_fpagetab;              // Offset of Fixup Page Table
  DWORD e32_frectab;               // Offset of Fixup Record Table
  DWORD e32_impmod;                // Offset of Import Module Name Table
  DWORD e32_impmodcnt;   // Number of entries in Import Module Name Table
  DWORD e32_impproc;     // Offset of Import Procedure Name Table
  DWORD e32_pagesum;     // Offset of Per-Page Checksum Table
  DWORD e32_datapage;    // Offset of Enumerated Data Pages
  DWORD e32_preload;     // Number of preload pages
  DWORD e32_nrestab;     // Offset of Non-resident Names Table
  DWORD e32_cbnrestab;   // Size of Non-resident Name Table
  DWORD e32_nressum;     // Non-resident Name Table Checksum
  DWORD e32_autodata;    // Object # for automatic data object
  DWORD e32_debuginfo;   // Offset of the debugging information
  DWORD e32_debuglen;    // The length of the debugging info. in bytes
  DWORD e32_instpreload; // Number of instance pages in preload section of VXD
                         // file
  DWORD e32_instdemand;  // Number of instance pages in demand load section of
                         // VXD file
  DWORD e32_heapsize;    // Size of heap - for 16-bit apps
  BYTE e32_res3[12];     // Reserved words
  DWORD e32_winresoff;
  DWORD e32_winreslen;
  WORD e32_devid;  // Device ID for VxD
  WORD e32_ddkver; // DDK version for VxD
} IMAGE_VXD_HEADER, *PIMAGE_VXD_HEADER;

typedef struct _IMAGE_FILE_HEADER {
  WORD Machine;
  WORD NumberOfSections;
  DWORD TimeDateStamp;
  DWORD PointerToSymbolTable;
  DWORD NumberOfSymbols;
  WORD SizeOfOptionalHeader;
  WORD Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;

#define IMAGE_SIZEOF_FILE_HEADER 20

#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file.
#define IMAGE_FILE_EXECUTABLE_IMAGE                                            \
  0x0002 // File is executable  (i.e. no unresolved external references).
#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line nunbers stripped from file.
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED                                         \
  0x0008 // Local symbols stripped from file.
#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 // Aggressively trim working set
#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 // App can handle >2gb addresses
#define IMAGE_FILE_BYTES_REVERSED_LO                                           \
  0x0080 // Bytes of machine word are reversed.
#define IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine.
#define IMAGE_FILE_DEBUG_STRIPPED                                              \
  0x0200 // Debugging info stripped from file in .DBG file
#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP                                     \
  0x0400 // If Image is on removable media, copy and run from the swap file.
#define IMAGE_FILE_NET_RUN_FROM_SWAP                                           \
  0x0800 // If Image is on Net, copy and run from the swap file.
#define IMAGE_FILE_SYSTEM 0x1000 // System File.
#define IMAGE_FILE_DLL 0x2000 // File is a DLL.
#define IMAGE_FILE_UP_SYSTEM_ONLY                                              \
  0x4000 // File should only be run on a UP machine
#define IMAGE_FILE_BYTES_REVERSED_HI                                           \
  0x8000 // Bytes of machine word are reversed.

#define IMAGE_FILE_MACHINE_UNKNOWN 0
#define IMAGE_FILE_MACHINE_TARGET_HOST                                         \
  0x0001 // Useful for indicating we want to interact with the host and not a
         // WoW guest.
#define IMAGE_FILE_MACHINE_I386 0x014c // Intel 386.
#define IMAGE_FILE_MACHINE_R3000 0x0162 // MIPS little-endian, 0x160 big-endian
#define IMAGE_FILE_MACHINE_R4000 0x0166 // MIPS little-endian
#define IMAGE_FILE_MACHINE_R10000 0x0168 // MIPS little-endian
#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 // MIPS little-endian WCE v2
#define IMAGE_FILE_MACHINE_ALPHA 0x0184 // Alpha_AXP
#define IMAGE_FILE_MACHINE_SH3 0x01a2 // SH3 little-endian
#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3
#define IMAGE_FILE_MACHINE_SH3E 0x01a4 // SH3E little-endian
#define IMAGE_FILE_MACHINE_SH4 0x01a6 // SH4 little-endian
#define IMAGE_FILE_MACHINE_SH5 0x01a8 // SH5
#define IMAGE_FILE_MACHINE_ARM 0x01c0 // ARM Little-Endian
#define IMAGE_FILE_MACHINE_THUMB 0x01c2 // ARM Thumb/Thumb-2 Little-Endian
#define IMAGE_FILE_MACHINE_ARMNT 0x01c4 // ARM Thumb-2 Little-Endian
#define IMAGE_FILE_MACHINE_AM33 0x01d3
#define IMAGE_FILE_MACHINE_POWERPC 0x01F0 // IBM PowerPC Little-Endian
#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1
#define IMAGE_FILE_MACHINE_IA64 0x0200 // Intel 64
#define IMAGE_FILE_MACHINE_MIPS16 0x0266 // MIPS
#define IMAGE_FILE_MACHINE_ALPHA64 0x0284 // ALPHA64
#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 // MIPS
#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 // MIPS
#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64
#define IMAGE_FILE_MACHINE_TRICORE 0x0520 // Infineon
#define IMAGE_FILE_MACHINE_CEF 0x0CEF
#define IMAGE_FILE_MACHINE_EBC 0x0EBC // EFI Byte Code
#define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8)
#define IMAGE_FILE_MACHINE_M32R 0x9041 // M32R little-endian
#define IMAGE_FILE_MACHINE_ARM64 0xAA64 // ARM64 Little-Endian
#define IMAGE_FILE_MACHINE_CEE 0xC0EE

//
// Directory format.
//

typedef struct _IMAGE_DATA_DIRECTORY {
  DWORD VirtualAddress;
  DWORD Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16

//
// Optional header format.
//

typedef struct _IMAGE_OPTIONAL_HEADER {
  //
  // Standard fields.
  //

  WORD Magic;
  BYTE MajorLinkerVersion;
  BYTE MinorLinkerVersion;
  DWORD SizeOfCode;
  DWORD SizeOfInitializedData;
  DWORD SizeOfUninitializedData;
  DWORD AddressOfEntryPoint;
  DWORD BaseOfCode;
  DWORD BaseOfData;

  //
  // NT additional fields.
  //

  DWORD ImageBase;
  DWORD SectionAlignment;
  DWORD FileAlignment;
  WORD MajorOperatingSystemVersion;
  WORD MinorOperatingSystemVersion;
  WORD MajorImageVersion;
  WORD MinorImageVersion;
  WORD MajorSubsystemVersion;
  WORD MinorSubsystemVersion;
  DWORD Win32VersionValue;
  DWORD SizeOfImage;
  DWORD SizeOfHeaders;
  DWORD CheckSum;
  WORD Subsystem;
  WORD DllCharacteristics;
  DWORD SizeOfStackReserve;
  DWORD SizeOfStackCommit;
  DWORD SizeOfHeapReserve;
  DWORD SizeOfHeapCommit;
  DWORD LoaderFlags;
  DWORD NumberOfRvaAndSizes;
  IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;

typedef struct _IMAGE_ROM_OPTIONAL_HEADER {
  WORD Magic;
  BYTE MajorLinkerVersion;
  BYTE MinorLinkerVersion;
  DWORD SizeOfCode;
  DWORD SizeOfInitializedData;
  DWORD SizeOfUninitializedData;
  DWORD AddressOfEntryPoint;
  DWORD BaseOfCode;
  DWORD BaseOfData;
  DWORD BaseOfBss;
  DWORD GprMask;
  DWORD CprMask[4];
  DWORD GpValue;
} IMAGE_ROM_OPTIONAL_HEADER, *PIMAGE_ROM_OPTIONAL_HEADER;

typedef struct _IMAGE_OPTIONAL_HEADER64 {
  WORD Magic;
  BYTE MajorLinkerVersion;
  BYTE MinorLinkerVersion;
  DWORD SizeOfCode;
  DWORD SizeOfInitializedData;
  DWORD SizeOfUninitializedData;
  DWORD AddressOfEntryPoint;
  DWORD BaseOfCode;
  ULONGLONG ImageBase;
  DWORD SectionAlignment;
  DWORD FileAlignment;
  WORD MajorOperatingSystemVersion;
  WORD MinorOperatingSystemVersion;
  WORD MajorImageVersion;
  WORD MinorImageVersion;
  WORD MajorSubsystemVersion;
  WORD MinorSubsystemVersion;
  DWORD Win32VersionValue;
  DWORD SizeOfImage;
  DWORD SizeOfHeaders;
  DWORD CheckSum;
  WORD Subsystem;
  WORD DllCharacteristics;
  ULONGLONG SizeOfStackReserve;
  ULONGLONG SizeOfStackCommit;
  ULONGLONG SizeOfHeapReserve;
  ULONGLONG SizeOfHeapCommit;
  DWORD LoaderFlags;
  DWORD NumberOfRvaAndSizes;
  IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;

#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107

typedef struct _IMAGE_NT_HEADERS64 {
  DWORD Signature;
  IMAGE_FILE_HEADER FileHeader;
  IMAGE_OPTIONAL_HEADER64 OptionalHeader;
} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;

typedef struct _IMAGE_NT_HEADERS {
  DWORD Signature;
  IMAGE_FILE_HEADER FileHeader;
  IMAGE_OPTIONAL_HEADER32 OptionalHeader;
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;

typedef struct _IMAGE_ROM_HEADERS {
  IMAGE_FILE_HEADER FileHeader;
  IMAGE_ROM_OPTIONAL_HEADER OptionalHeader;
} IMAGE_ROM_HEADERS, *PIMAGE_ROM_HEADERS;

// IMAGE_FIRST_SECTION doesn't need 32/64 versions since the file header is the
// same either way.

#define IMAGE_FIRST_SECTION(ntheader)                                          \
  ((PIMAGE_SECTION_HEADER)((ULONG_PTR)(ntheader) +                             \
                           FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) +    \
                           ((ntheader))->FileHeader.SizeOfOptionalHeader))

// Subsystem Values

#define IMAGE_SUBSYSTEM_UNKNOWN 0 // Unknown subsystem.
#define IMAGE_SUBSYSTEM_NATIVE 1 // Image doesn't require a subsystem.
#define IMAGE_SUBSYSTEM_WINDOWS_GUI                                            \
  2 // Image runs in the Windows GUI subsystem.
#define IMAGE_SUBSYSTEM_WINDOWS_CUI                                            \
  3 // Image runs in the Windows character subsystem.
#define IMAGE_SUBSYSTEM_OS2_CUI 5 // image runs in the OS/2 character subsystem.
#define IMAGE_SUBSYSTEM_POSIX_CUI                                              \
  7 // image runs in the Posix character subsystem.
#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS 8 // image is a native Win9x driver.
#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI                                         \
  9 // Image runs in the Windows CE subsystem.
#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 //
#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 //
#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 //
#define IMAGE_SUBSYSTEM_EFI_ROM 13
#define IMAGE_SUBSYSTEM_XBOX 14
#define IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION 16
#define IMAGE_SUBSYSTEM_XBOX_CODE_CATALOG 17

// DllCharacteristics Entries

//      IMAGE_LIBRARY_PROCESS_INIT            0x0001     // Reserved.
//      IMAGE_LIBRARY_PROCESS_TERM            0x0002     // Reserved.
//      IMAGE_LIBRARY_THREAD_INIT             0x0004     // Reserved.
//      IMAGE_LIBRARY_THREAD_TERM             0x0008     // Reserved.
#define IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA                               \
  0x0020 // Image can handle a high entropy 64-bit virtual address space.
#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040 // DLL can move.
#define IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY 0x0080 // Code Integrity Image
#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100 // Image is NX compatible
#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION                                  \
  0x0200 // Image understands isolation and doesn't want it
#define IMAGE_DLLCHARACTERISTICS_NO_SEH                                        \
  0x0400 // Image does not use SEH.  No SE handler may reside in this image
#define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 // Do not bind this image.
#define IMAGE_DLLCHARACTERISTICS_APPCONTAINER                                  \
  0x1000 // Image should execute in an AppContainer
#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 // Driver uses WDM model
#define IMAGE_DLLCHARACTERISTICS_GUARD_CF                                      \
  0x4000 // Image supports Control Flow Guard.
#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000

// Directory Entries

#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory
#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory
#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table
#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory
//      IMAGE_DIRECTORY_ENTRY_COPYRIGHT       7   // (X86 usage)
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP
#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT                                     \
  11 // Bound Import Directory in headers
#define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor

//
// Section header format.
//

#define IMAGE_SIZEOF_SHORT_NAME 8

typedef struct _IMAGE_SECTION_HEADER {
  BYTE Name[IMAGE_SIZEOF_SHORT_NAME];
  union {
    DWORD PhysicalAddress;
    DWORD VirtualSize;
  } Misc;
  DWORD VirtualAddress;
  DWORD SizeOfRawData;
  DWORD PointerToRawData;
  DWORD PointerToRelocations;
  DWORD PointerToLinenumbers;
  WORD NumberOfRelocations;
  WORD NumberOfLinenumbers;
  DWORD Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

#define IMAGE_SIZEOF_SECTION_HEADER 40

#endif
